import json
import re

from django.conf import settings
from django_redis import get_redis_connection
from rest_framework import permissions, status
from rest_framework.exceptions import APIException
from rest_framework.permissions import BasePermission


class UserLock(APIException):
    status_code = status.HTTP_400_BAD_REQUEST
    default_detail = '用户已被锁定,请联系管理员'
    default_code = 'not_authenticated'


class RbacPermission(BasePermission):
    """
    自定义权限认证
    """
    @staticmethod
    def pro_uri(uri):
        '''
        让返回的路径为/path1/path2/path3/格式，确保路径开头和末尾都有/，使用/+将连续的去重
        :param uri:
        :return:
        '''
        #base_api = settings.BASE_API
        #uri = '/' + base_api + '/' + uri + '/'
        uri='/' + uri + '/'
        #print(re.sub('/+', '/', uri))
        return re.sub('/+', '/', uri) #去除多余的/号，让返回的路径符合标准格式

    def has_permission(self, request, view):
        if not request.user.is_active:
            raise UserLock()
        request_url = request.path
        # 如果请求url在白名单，放行
        for safe_url in settings.WHITE_LIST:
            #print(safe_url)
            #print(request_url)
            if re.match(settings.REGEX_URL.format(url=self.pro_uri(safe_url)), request_url):
                #print("白名单放行")
                return True



        #从mysql中读取数据
        # permissionlist=Permission.objects.values_list("path",flat=True)
        # #print(permissionlist)
        # if request_url not in permissionlist:
        #     print("请求路径不在权限控制中，通过")
        #     return  True
        #遍历用户所属角色，再遍历每个角色拥有的权限的路径和方法，如果匹配则通过
        # for roleitem in request.user.role.all().prefetch_related('permission'):
        #     for permissionitem in roleitem.permission.all():
        #         #print(permissionitem.path)
        #         #print(permissionitem.name)
        #         #print(permissionitem.method)
        #         if permissionitem.method == request.method and request.path.startswith(permissionitem.path):
        #             #print(True)
        #             return True
        # return False


        # 从redis中读取信息
        conn = get_redis_connection('user_info')
        if not conn.exists('user_permissions_manage'):
            redis_storage_permissions(conn)
        if conn.exists('user_info_%s' % request.user.id):
             user_permissions = json.loads(conn.hget('user_info_%s' % request.user.id, 'permission').decode())
             # if 'admin' in user_permissions:
             #     return True
        else:
             user_permissions = []
             # if 'admin' in request.user.roles.values_list('name', flat=True):
             #     return True
        # RBAC权限验证
        # Step 1
        request_method = request.method
        #获取全部的路径列表 [b'/api/v1/rbac/test2/', b'/api/v1/rbac/test4/', b'/', b'/api/v1/rbac/test/', b'/TEST']
        url_keys = conn.hkeys('user_permissions_manage')
        permissions=[]
        #[{'method': 'GET', 'sign': 'GET_/', 'id': 1}, {'method': 'POST', 'sign': 'POST_/', 'id': 3}, {'method': 'DELETE', 'sign': 'DELETE_/', 'id': 4}, {'method': 'PUT', 'sign': 'PUT_/', 'id': 9}, {'method': 'POST', 'sign': '123456789', 'id': 11}, {'method': 'GET', 'sign': 'GET_/api/v1/rbac/test/', 'id': 14}, {'method': 'POST', 'sign': 'POST_/api/v1/rbac/test/', 'id': 8}]
        #遍历权限中的所有路径，如果有匹配请求路径开头的，则获取该路径的所有权限放入permissions列表中
        for url_key in url_keys:
            if self.pro_uri(request_url).startswith(url_key.decode()):
                redis_key=url_key.decode()
                permissions.extend(json.loads(conn.hget('user_permissions_manage', redis_key).decode()))
        #print(permissions)

        #遍历匹配到的路径的全部权限，如果方法和标识都匹配，则通过
        for permission in permissions:
                if permission.get('method') == request_method and permission.get('sign') in user_permissions:
                    return True
        return  False




class IsSchoolOwnerOrHospitalOwner(permissions.BasePermission):
    """
    对象级权限仅允许对象的所有者对其进行编辑
    假设模型实例具有`owner`属性。
    """

    def has_object_permission(self, request, view, obj):
        # 任何请求都允许读取权限，
        # 所以我们总是允许GET，HEAD或OPTIONS 请求.
        # if request.method in permissions.SAFE_METHODS:
        #     return True

        # 示例必须要有一个名为`owner`的属性
        return request.user.is_superuser or obj.batch.school.user == request.user or obj.batch.hospital.user